# uniform mutation

import geatpy as ea
import numpy as np
import random


# 生成初始种群，不允许重复
def generate(pop_num, chrom_len, lb, ub):
    # 生成[lb, ub+1)之间的所有整数
    index = np.arange(lb, ub+1, 1, dtype=int)
    pop = np.random.choice(index, size=(pop_num, chrom_len), replace=False)
    return pop


# 适应度函数，score越小，适应度越大
# score必须是一个n行1列的向量
def rank(score):
    return ea.ranking(score)


# stochastic universal sampling
# fitness越大越好
def select(fitness, sel_num):
    """
    选择函数
    :param fitness: 形状为n*1的numpy array，存储着对应个体的适应度。越大越好
    :param sel_num: 整型，被选择出来的数量
    :return: 被选中个体的下标
    """
    # 种群数量
    pop_num = fitness.shape[0]
    # 将fitness从numpy的array转为列表
    fitness_list = fitness.reshape(1, pop_num).tolist()[0]
    # 绑定下标
    fitness_to_index = zip(fitness_list, range(pop_num))
    # 从小到大排序
    fitness_to_index = sorted(fitness_to_index, key=lambda x: x[0])
    sum_fit = sum(fitness)[0]
    dist = sum_fit / float(sel_num)
    start = random.uniform(0, dist)
    points = [start + i*dist for i in range(sel_num)]
    chosen = []
    for p in points:
        i = 0
        sum_ = fitness[i, 0]
        while sum_ < p:
            i += 1
            sum_ += fitness[i, 0]
        chosen.append(i)
    print(chosen)
    return chosen





if __name__ == "__main__":
    pop_num = 10
    chrom_len = 10
    pop = generate(pop_num, chrom_len, 0, 19999)
    score = np.random.random(pop_num)
    score = score.reshape(pop_num, 1)
    fitness = rank(score)
    select(fitness, pop_num)

